package com.bjsxt.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bjsxt.domain.SysMenu;
import com.bjsxt.domain.SysRolePrivilege;
import com.bjsxt.dto.RolePrivilegesParam;
import com.bjsxt.mapper.SysRolePrivilegeMapper;
import com.bjsxt.model.SysMenuVo;
import com.bjsxt.service.SysMenuService;
import com.bjsxt.service.SysPrivilegeService;
import com.bjsxt.service.SysRolePrivilegeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class SysRolePrivilegeServiceImpl extends ServiceImpl<SysRolePrivilegeMapper, SysRolePrivilege> implements SysRolePrivilegeService {

    /**
     * 菜单业务层接口
     */
    @Autowired
    private SysMenuService sysMenuService;

    /**
     * 权限业务层接口
     */
    @Autowired
    private SysPrivilegeService sysPrivilegeService;

    /**
     * 角色权限中间表 mapper 接口
     */
    @Autowired
    private SysRolePrivilegeMapper sysRolePrivilegeMapper;

    /**
     * 根据角色 id 查询菜单权限列表数据
     *
     * @param roleId 角色 id
     * @return 菜单权限列表数据
     */
    @Override
    public List<SysMenuVo> findSysMenuAndPrivileges(Long roleId) {
        // 首选查询所有的菜单
        List<SysMenu> sysMenus = sysMenuService.list();
        // 如果查询的菜单数据是空的, 返回空集合
        if (CollectionUtil.isEmpty(sysMenus)) return Collections.EMPTY_LIST;
        //我们需要拿出一级菜单的数据
        List<SysMenu> rootMenus = sysMenus.stream().filter(sysMenu -> sysMenu.getParentId() == null).collect(Collectors.toList());
        //如果获取的一级菜单是空的数据,返回空的集合
        if (CollectionUtil.isEmpty(rootMenus)) return Collections.EMPTY_LIST;
        // 创建二级菜单的集合
        List<SysMenuVo> subMenus = new ArrayList<>();
        // 根据一级菜单查询所有的二级菜单
        for (SysMenu menu : rootMenus) {
            // 添加集合进入二级菜单集合中
            subMenus.addAll(getChildMenus(menu.getId(), roleId, sysMenus));
        }
        // 返回二级菜单
        return subMenus;
    }

    /**
     * 根据传入的权限数据对象进行权限的授予
     *
     * @param rolePrivilegesParam 权限数据对象
     * @return 是否授予成功 true: 成功 , false: 失败
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean grantPrivileges(RolePrivilegesParam rolePrivilegesParam) {
        // 获取需要更新的角色的 id
        Long roleId = rolePrivilegesParam.getRoleId();
        // 为了防止数据的麻烦进行更新, 在这里做的是全删除再添加操作, 避免比对操作
        // 调用当前的业务层代码进行数据的删除操作
        remove(new LambdaQueryWrapper<SysRolePrivilege>().eq(SysRolePrivilege::getRoleId, roleId));
        // 获取权限数据 id 集合
        List<Long> privilegeIds = rolePrivilegesParam.getPrivilegeIds();
        // 使用流进行 list 的转换
        List<SysRolePrivilege> sysRolePrivileges = privilegeIds.stream().map(id -> new SysRolePrivilege(null, roleId, id)).collect(Collectors.toList());
        // 进行值的添加并返回结果
        return saveBatch(sysRolePrivileges);
    }

    /**
     * 根据角色 ID 删除角色权限数据
     *
     * @param roleId 角色 ID
     * @return true 删除成功 false 删除失败
     */
    @Override
    public boolean removeByRoleId(Long roleId) {
        // 创建进行数据筛选的对象
        QueryWrapper<SysRolePrivilege> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(SysRolePrivilege.COL_ROLE_ID, roleId);
        // 进行数据的移除操作
        return remove(queryWrapper);
    }

    /**
     * 查询该菜单的子菜单
     *
     * @param parentId 父菜单 id
     * @param roleId   角色 id
     * @param sources  全部的菜单数据
     * @return 子菜单集合
     */
    private List<SysMenuVo> getChildMenus(Long parentId, Long roleId, List<SysMenu> sources) {
        //创建子集合数据的对象
        List<SysMenuVo> childs = new ArrayList<>();
        //根据角色 id 查询对应的权限 id 集合
        Set<Long> rolePrivilegesIds = sysRolePrivilegeMapper.getPrivilegesByRoleId(roleId);
        //遍历全部的菜单数据
        for (SysMenu menu : sources) {
            //如果菜单数据的父亲 id 等于传入的父亲 id 就是该菜单的子数据
            if (menu.getParentId() == parentId) {
                //进行添加的数据对象的创建
                SysMenuVo sysMenuVo = new SysMenuVo();
                //进行值的 copy
                BeanUtil.copyProperties(menu, sysMenuVo);
                // 设置该菜单的子菜单数据
                sysMenuVo.setChilds(getChildMenus(menu.getId(), roleId, sources));
                // 设置该菜单的权限数据, 设置该菜单的对应权限数据
                sysMenuVo.setPrivileges(sysPrivilegeService.getAllSysPrivilege(menu.getId(), rolePrivilegesIds));
                //添加入集合对象中
                childs.add(sysMenuVo);
            }
        }
        // 返回菜单数据
        return childs;
    }
}
